﻿using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Xml.Linq;
using AjaxControlToolkit;
using Formsy.Config;
using Formsy.Providers.DataSource;
using Formsy.Common;
using System.Text;
using Formsy.Core.Resources;


namespace Formsy.Core
{
    /// <summary>
    /// Creates standard and custom controls.
    /// 
    /// I've been really into regions lately. This is excessive. I know. 
    /// </summary>
    public class ControlBuilder
    {
        #region Flags

        // Flags so we only inject script once
        protected bool hasScript = false;
        protected bool hasScriptManager = false;

        #endregion



        #region CreateHtmlControl

        /// <summary>
        /// Creates a HtmlGenericControl with given tag, label and class.
        /// Label is added as a 2nd class.
        /// </summary>
        /// <param name="controlType"></param>
        /// <param name="label"></param>
        /// <param name="cssClass"></param>
        /// <returns></returns>
        public HtmlGenericControl CreateHtmlControl(string controlType, string name, string cssClass)
        {
            HtmlGenericControl control = new HtmlGenericControl(controlType);

            if (!string.IsNullOrEmpty(cssClass.Flatten()))
                AddClass(control, cssClass.Flatten());

            if (!string.IsNullOrEmpty(name.Flatten()))
                AddClass(control, name.Flatten());

            return control;
        }


        #endregion



        #region CreateButton

        /// <summary>
        /// Creates a button
        /// </summary>
        /// <param name="name"></param>
        /// <param name="validationGroup"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        public Button CreateButton(string name, string validationGroup, string text)
        {
            Button button = CreateButton(ControlBuilderHelper.CreateId(ControlType.Button, name), text);
            button.ValidationGroup = validationGroup;
            return button;
        }

        #endregion



        #region CreateLabel

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="associatedControlID"></param>
        /// <param name="suffix"></param>
        /// <returns></returns>
        public Label CreateLabel(string name, string associatedControlID, string suffix)
        {
            Label lable = (Label)CreateITextControl(name, new Label(), ControlType.Label, suffix);
            lable.AssociatedControlID = associatedControlID;
            return lable;
        }

        #endregion



        #region CreateLiteral

        /// <summary>
        /// Create a literal inside a span.
        /// </summary>
        /// <param name="field"></param>
        /// <param name="name"></param>
        /// <param name="formFields"></param>
        /// <returns></returns>
        public HtmlGenericControl CreateLiteral(string name, string text)
        {
            HtmlGenericControl span = new HtmlGenericControl("span");
            Literal lit = new Literal();
            lit.Text = text;
            lit.ID = ControlBuilderHelper.CreateId(ControlType.Literal, name);
            AddTypeAsClass(span, name.Flatten());

            // formFields.Add(new FormField(lit.ID, name, lit, null, ControlType.Literal));
            span.Controls.Add(lit);
            return span;
        }

        #endregion



        #region CreateLink

        /// <summary>
        /// Creates a HtmlAnchor.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="href"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        public HtmlAnchor CreateLink(string name, string href, string text)
        {
            HtmlAnchor link = new HtmlAnchor();
            link.ID = ControlBuilderHelper.CreateId(ControlType.Link, name);
            link.HRef = href;
            link.InnerText = text;

            return link;
        }

        #endregion



        #region CreateTextBox
        /// <summary>
        /// Creates a TextBox.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="nameSuffix"></param>
        /// <returns></returns>
        public TextBox CreateTextBox(string name, string nameSuffix)
        {
            TextBox textbox = (TextBox)CreateControl(name, new TextBox(), ControlType.TextBox, nameSuffix);
            return textbox;
        }

        #endregion



        #region CreateImage

        public HtmlImage CreateHtmlImage(string name, string url, string title, string alt)
        {
            HtmlImage image = new HtmlImage();
            image.ID = name;
            image.Src = url;
            image.Attributes.Add("title", title);
            image.Alt = alt;

            return image;
        }

        #endregion



        #region CreateTextArea
        /// <summary>
        /// Creates a TextBox with TextMode = TextBoxMode.MiltiLine
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public TextBox CreateTextArea(string name)
        {
            TextBox textbox = (TextBox)CreateControl(name, new TextBox(), ControlType.TextArea, string.Empty);
            textbox.TextMode = TextBoxMode.MultiLine;
            return textbox;
        }

        #endregion



        #region CreateCheckBox
        /// <summary>
        /// Creates a CheckBox.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public CheckBox CreateCheckBox(string name)
        {
            CheckBox checkbox = (CheckBox)CreateControl(name, new CheckBox(), ControlType.CheckBox, string.Empty);
            return checkbox;
        }

        #endregion



        #region CreateRadioButton
        /// <summary>
        /// Creates a RadioButton
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public RadioButton CreateRadioButton(string name)
        {
            RadioButton radio = (RadioButton)CreateControl(name, new RadioButton(), ControlType.RadioButton, string.Empty);
            return radio;
        }

        #endregion



        #region CreateHiddenField
        /// <summary>
        /// Creates HiddenField with given name and initial value.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public HiddenField CreateHiddenField(string name, string value)
        {
            HiddenField hiddenField = (HiddenField)CreateControl(name, new HiddenField(), ControlType.HiddenField, string.Empty);
            hiddenField.Value = value;

            return hiddenField;
        }

        #endregion


        #region CreateHtmlHiddenField
        /// <summary>
        /// Creates HtmlInputHidden with given name and initial value.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public HtmlInputHidden CreateHtmlHiddenField(string name, string value)
        {
            HtmlInputHidden hidden = new HtmlInputHidden();
            string s = ("hiddenfield" + name).Flatten();
            hidden.Name = s;
            hidden.Value = value;
            hidden.ID = s;

            //HiddenField hiddenField = (HiddenField)CreateControl(name, new HiddenField(), ControlType.HiddenField, string.Empty);
            //hiddenField.Value = value;

            return hidden;
        }

        #endregion


        #region CreatePasswordField
        /// <summary>
        /// Creates a TextBox with TextMode = TextBoxMode.Password.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="nameSuffix"></param>
        /// <returns></returns>
        public TextBox CreatePasswordField(string name, string nameSuffix)
        {
            TextBox textbox = CreateTextBox(name, nameSuffix);
            textbox.TextMode = TextBoxMode.Password;
            return textbox;
        }

        #endregion



        #region CreateDropDownList

        public DropDownList CreateDropDownList(XElement field)
        {
            DropDownList ddl = (DropDownList)CreateListControl(field, new DropDownList(), ControlType.DropDownList);
            return ddl;
        }

        #endregion



        #region CreateRadioButtonList

        public RadioButtonList CreateRadioButtonList(XElement field)
        {
            RadioButtonList rbl = (RadioButtonList)CreateListControl(field, new RadioButtonList(), ControlType.RadioButtonList);
            return rbl;
        }

        #endregion



        #region CreateCheckBoxList

        public CheckBoxList CreateCheckBoxList(XElement field)
        {
            CheckBoxList cbl = (CheckBoxList)CreateListControl(field, new CheckBoxList(), ControlType.CheckBoxList);
            return cbl;
        }

        #endregion



        #region CreateFileUpload

        public HtmlGenericControl CreateFileUpload(XElement field, HtmlGenericControl div, List<FormField> formFields, string formName, string scriptName, HtmlGenericControl fieldSet)
        {
            FileUpload ful = (FileUpload)CreateControl(field.GetName(), new FileUpload(), ControlType.FileUpload, string.Empty);

            // create label
            Label label = CreateLabel(field.GetName(), ful.ID, string.Empty);
            div.Controls.Add(label);
            div.Controls.Add(ful);

            // create validators
            CreateValidators(field, formName, fieldSet, div, ful, formFields, string.Empty);

            // inject script to clear the file upload box
            if (hasScript == false)
            {
                AddResource(EmbededResource.FormScript, ResourceType.Script);
                hasScript = true;
            }

            // create clear button - why doesn't .net have this by default???? 
            Button btn = CreateButton(ControlType.Button + ful.ID, "Clear");
            btn.OnClientClick = "return " + scriptName + "('" + ful.ClientID + "');";
            div.Controls.Add(btn);

            // get valid extensions
            string[] validExtensions = field.Attribute("ValidExtensions").Value.Split(",".ToCharArray());

            formFields.Add(new FormField(ful.ID, label.Text, ful, label, ControlType.FileUpload, validExtensions));
            return div;
        }
        #endregion



        #region CreateDatePicker

        /// <summary>
        /// Creates a Textbox with a CalendarExtender and Label.
        /// No validator is defined in this method.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="div"></param>
        /// <param name="mainContainer"></param>
        /// <param name="formFields"></param>
        /// <param name="formName"></param>
        /// <param name="fieldSet"></param>
        /// <returns></returns>
        public HtmlGenericControl CreateDatePicker(string name, HtmlGenericControl div, Control mainContainer, List<FormField> formFields, string formName, HtmlGenericControl fieldSet, string validatorType, string validatorText, string validatorMessage, string validatorDisplay, bool validatorEnabled)
        {
            // create an XElement so we can reuse CreateDatePicker()...this is where my self-parsing design pattern gets annoying!
            XElement field = new XElement(name);
            field.SetAttributeValue("Type", "DatePicker");
            field.SetAttributeValue("Name", name);

            if (validatorEnabled) 
            {
                // add validator XElement
                XElement val = new XElement("Validator");
                val.SetAttributeValue("Type", validatorType);
                val.SetAttributeValue("Text", validatorText);
                val.SetAttributeValue("ErrorMessage", validatorMessage);
                val.SetAttributeValue("Display", validatorDisplay);
                field.Add(val);
            }

            div = CreateDatePicker(field, div, mainContainer, formFields, formName, fieldSet);

            return div;
        }


        /// <summary>
        /// Creates a Textbox with a CalendarExtender and Label.
        /// Validators are defined in the Xml of the field parameter. 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="div"></param>
        /// <param name="mainContainer"></param>
        /// <param name="formFields"></param>
        /// <param name="formName"></param>
        /// <param name="fieldSet"></param>
        /// <returns></returns>

        public HtmlGenericControl CreateDatePicker(XElement field, HtmlGenericControl div, Control mainContainer, List<FormField> formFields, string formName, HtmlGenericControl fieldSet)
        {
            if (!hasScriptManager)
            {
                ScriptManager sm = new ScriptManager();
                mainContainer.Controls.Add(sm);
                hasScriptManager = true;
            }
            TextBox textbox = CreateTextBox(field.GetName(), string.Empty);

            // add a nice calendar extender
            CalendarExtender ce = new CalendarExtender();
            ce.TargetControlID = textbox.ClientID;
            div.Controls.Add(ce);

            // create and add a label
            Label label = CreateLabel(field.GetName(), textbox.ID, string.Empty);
            div.Controls.Add(label);
            div.Controls.Add(textbox);

            // add class for targetting
            AddTypeAsClass(div, ControlType.TextBox.Flatten());
           
            // save the field
            formFields.Add(new FormField(textbox.ID, label.Text, textbox, label, field.GetFieldType(), false));
           
            // add validators
            CreateValidators(field, formName, fieldSet, div, textbox, formFields, string.Empty);

            //TODO: should this go before the CreateValidators() ?
            // note that in CreateValidators() we have this: formFields.Last().AddFieldValidator(val, validatorType);

             return div;
        }
        #endregion



        #region CreatePasswordPair


        public HtmlGenericControl CreatePasswordPair(XElement field, HtmlGenericControl div, string formName, List<FormField> formFields, HtmlGenericControl fieldSet)
        {
            string suffix = "Confirm";
            string name = field.GetName();

            // create first password field with containing div
            HtmlGenericControl divPassword = CreateHtmlControl(ControlType.Div, name, ClientStrings.Default.FieldClass);
            TextBox password = CreatePasswordField(field.GetName(), string.Empty);
            Label lblPassword = CreateLabel(field.GetName(), password.ID, string.Empty);
            string label = field.GetAttributeOrDefault("Label");
            if (!string.IsNullOrEmpty(label))
                lblPassword.Text = label;

            divPassword.Controls.Add(lblPassword);
            divPassword.Controls.Add(password);
            // add class for targetting
            AddTypeAsClass(divPassword, ControlType.TextBox.Flatten());

            // create second password field with containing div
            HtmlGenericControl divPasswordConf = CreateHtmlControl(ControlType.Div, name + suffix, ClientStrings.Default.FieldClass);
            TextBox passwordConf = CreatePasswordField(field.GetName(), suffix);
            Label lblPasswordConf = CreateLabel(field.GetName(), passwordConf.ID, suffix);
            if (!string.IsNullOrEmpty(label))
                lblPasswordConf.Text = suffix + " " + label;


            divPasswordConf.Controls.Add(lblPasswordConf);
            divPasswordConf.Controls.Add(passwordConf);
            // add class for targetting
            AddTypeAsClass(divPasswordConf, ControlType.TextBox.Flatten());

            // add the divs
            fieldSet.Controls.Add(divPassword);
            fieldSet.Controls.Add(divPasswordConf);

            // save the fields
            formFields.Add(new FormField(password.ID, name, password, lblPassword, field.GetFieldType(), false));
            formFields.Add(new FormField(passwordConf.ID, name, passwordConf, lblPasswordConf, field.GetFieldType(), true));

            // add validator to containing div
            List<XElement> validators = field.Descendants("Validator").ToList();
            var xmlCompare = validators
                                .Where(x => x.Attribute("Type") != null)
                                .Where(x => x.Attribute("Type").Value == "CompareValidator").FirstOrDefault();
            if (xmlCompare == null)
            {
                // add default values
                xmlCompare = new XElement("CompareValidator");
                xmlCompare.Add(new XAttribute("Text", "*"));
                xmlCompare.Add(new XAttribute("ErrorMessage", "Passwords must match"));
                xmlCompare.Add(new XAttribute("Display", "Dynamic"));
            }

            // add compare validator to the second text field
            var val = CreateCompareValidator(xmlCompare, password, name, formName, ControlType.TextBox, passwordConf.ID);
            divPasswordConf.Controls.Add(val);
            formFields.LastOrDefault().AddFieldValidator(val, ControlType.CompareValidator);

            CreateValidators(field, formName, fieldSet, divPassword, password, formFields, string.Empty);
            CreateValidators(field, formName, fieldSet, divPasswordConf, passwordConf, formFields, suffix);

            return fieldSet;
        }



        #endregion




        #region CreateEmailPair

        public HtmlGenericControl CreateEmailPair(XElement field, HtmlGenericControl div, string formName, List<FormField> formFields, HtmlGenericControl fieldSet)
        {
            string suffix = "Confirm";
            string name = field.GetName();

            // create first email field with containing div
            HtmlGenericControl divEmail = CreateHtmlControl(ControlType.Div, name, ClientStrings.Default.FieldClass);
            TextBox email = CreateTextBox(field.GetName(), string.Empty);
            Label lblEmail = CreateLabel(field.GetName(), email.ID, string.Empty);

            string label = field.GetAttributeOrDefault("Label");
            if (!string.IsNullOrEmpty(label))
                lblEmail.Text = label;

            divEmail.Controls.Add(lblEmail);
            divEmail.Controls.Add(email);

            // add class for targetting
            AddTypeAsClass(divEmail, ControlType.TextBox.Flatten());

            // create second email field with containing div
            HtmlGenericControl divEmailConf = CreateHtmlControl(ControlType.Div, name + suffix, ClientStrings.Default.FieldClass);
            TextBox emailConf = CreateTextBox(field.GetName(), suffix);
            Label lblEmailConf = CreateLabel(field.GetName(), emailConf.ID, suffix);
            if (!string.IsNullOrEmpty(label))
                lblEmailConf.Text = suffix + " " + label;

            divEmailConf.Controls.Add(lblEmailConf);
            divEmailConf.Controls.Add(emailConf);

            // add class for targetting
            AddTypeAsClass(divEmailConf, ControlType.TextBox.Flatten());

            // add the divs
            fieldSet.Controls.Add(divEmail);
            fieldSet.Controls.Add(divEmailConf);

            // save the fields
            formFields.Add(new FormField(email.ID, name, email, lblEmail, field.GetFieldType(), false));
            formFields.Add(new FormField(emailConf.ID, name, emailConf, lblEmailConf, field.GetFieldType(), true));

            // add validator to containing div
            List<XElement> validators = field.Descendants("Validator").ToList();
            var xmlCompare = validators
                                .Where(x => x.Attribute("Type") != null)
                                .Where(x => x.Attribute("Type").Value == ControlType.CompareValidator).FirstOrDefault();
            if (xmlCompare == null)
            {
                // add default values
                xmlCompare = new XElement(ControlType.CompareValidator);
                xmlCompare.Add(new XAttribute("Text", "*"));
                xmlCompare.Add(new XAttribute("ErrorMessage", "Email addresses must match"));
                xmlCompare.Add(new XAttribute("Display", "Dynamic"));
            }

            // add compare validator to the second text field
            var val = CreateCompareValidator(xmlCompare, email, name, formName, ControlType.TextBox, emailConf.ID);
            divEmailConf.Controls.Add(val);
            formFields.LastOrDefault().AddFieldValidator(val, ControlType.CompareValidator);

            // add validators
            CreateValidators(field, formName, fieldSet, divEmail, email, formFields, string.Empty);
            CreateValidators(field, formName, fieldSet, divEmailConf, emailConf, formFields, suffix);

            return fieldSet;
        }

        #endregion




        #region CreateValidators
        /// <summary>
        /// Parses Validator section of the field's xml.
        /// Iteratres through validators.
        /// Adds validators to the containing div.
        /// </summary>
        /// <param name="field"></param>
        /// <param name="formName"></param>
        /// <param name="fieldSet"></param>
        /// <param name="div"></param>
        /// <param name="inputControl"></param>
        /// <param name="formFields"></param>
        /// <param name="suffix"></param>
        public void CreateValidators(XElement field, string formName, HtmlGenericControl fieldSet, HtmlGenericControl div, Control inputControl, List<FormField> formFields, string suffix)
        {
            string name = field.GetName().Flatten();
            string inputType = field.GetFieldType();

            // Validators
            List<XElement> validators = field.Descendants("Validator").ToList();
            foreach (XElement v in validators)
            {
                // Type, Text and Error Message
                string validatorType = v.GetFieldType();

                BaseValidator val = null;
                // Validator
                if (validatorType == ControlType.RequiredFieldValidator)
                {
                    if (!ControlType.CanServerValidate(inputType)) // checkbox and radio buttons cannot contain normal validators so must inject js
                    {
                        val = CreateCustomValidator(v, inputControl, name, formName, inputType);

                        // inject javascript!
                        if (hasScript == false)
                        {
                            AddResource(EmbededResource.FormScript, ResourceType.Script);
                            hasScript = true;
                        }
                        ((CustomValidator)val).ClientValidationFunction = EmbededResource.FormCustomValidationFunction;
                    }
                    else
                        val = CreateRequiredFieldValidator(v, inputControl, name + suffix, formName, inputType);

                    // add "required" class
                    AddClass(div, "required");
                }
                else if (validatorType == ControlType.RegularExpressionValidator)
                {
                    string validationExpression = v.Attribute("ValidationExpression").Value;
                    val = CreateRegExValidator(v, inputControl, name, formName, inputType);
                }

                else if (validatorType == ControlType.CustomValidator)
                {
                    val = CreateCustomValidator(v, inputControl, name, formName, inputType);
                }

                // add validator to containing div
                if (val != null)
                {
                    div.Controls.Add(val);
                    
                    // add validator to formFields only when formFields is being used...ie not in admin or csv section!
                    if (formFields.Count > 0) 
                        formFields.Last().AddFieldValidator(val, validatorType);
                }
            }
        }

        #endregion



        #region CreateRequiredFieldValidator
        public RequiredFieldValidator CreateRequiredFieldValidator(Control controlToValidate, string label, string validationGroup, string inputType, string text, string errorMessage, string display)
        {
            XElement field = new XElement("RequiredFieldValidator");
            field.SetAttributeValue("Text", text);
            field.SetAttributeValue("ErrorMessage", errorMessage);
            field.SetAttributeValue("Display", display);

            RequiredFieldValidator req = CreateRequiredFieldValidator(field, controlToValidate, label, validationGroup, inputType);
            
            return req;
        }


        public RequiredFieldValidator CreateRequiredFieldValidator(XElement field, Control controlToValidate, string label, string validationGroup, string inputType)
        {
            RequiredFieldValidator req = (RequiredFieldValidator)CreateValidator(field, controlToValidate, new RequiredFieldValidator(), ControlType.RequiredFieldValidator, label, validationGroup, inputType);
            return req;
        }

        #endregion



        #region CreateRegExValidator

        public RegularExpressionValidator CreateRegExValidator(XElement field, Control controlToValidate, string label, string validationGroup, string inputType)
        {
            RegularExpressionValidator reg = (RegularExpressionValidator)CreateValidator(field, controlToValidate, new RegularExpressionValidator(), ControlType.RegularExpressionValidator, label, validationGroup, inputType);
            string validationExpression = field.Attribute("ValidationExpression").Value;
            reg.ValidationExpression = validationExpression;
            return reg;
        }

        #endregion



        #region CreateCustomValidator

        public CustomValidator CreateCustomValidator(XElement field, Control controlToValidate, string label, string validationGroup, string inputType)
        {
            CustomValidator cust = (CustomValidator)CreateValidator(field, controlToValidate, new CustomValidator(), ControlType.CustomValidator, label, validationGroup, inputType);
            return cust;
        }

        #endregion



        #region CreateCompareValidator

        public CompareValidator CreateCompareValidator(XElement field, Control controlToValidate, string label, string validationGroup, string inputType, string controlToCompare)
        {
            CompareValidator comp = (CompareValidator)CreateValidator(field, controlToValidate, new CompareValidator(), ControlType.CompareValidator, label, validationGroup, inputType);
            comp.ControlToCompare = controlToCompare;
            return comp;
        }

        #endregion



        #region CreateValidationSummary

        public ValidationSummary CreateValidationSummary(string validationGroup, string enabled)
        {
            ValidationSummary vs = new ValidationSummary();
            vs.ID = ControlBuilderHelper.CreateId(ControlType.ValidationSummary, validationGroup);
            vs.ValidationGroup = validationGroup;
            vs.Enabled = bool.Parse(enabled);
            return vs;
        }

        #endregion



        #region CreateValidator

        protected BaseValidator CreateValidator(XElement x, Control controlToValidate, BaseValidator validator, string type, string label, string validationGroup, string inputType)
        {
            // create id
            validator.ID = ControlBuilderHelper.CreateId(type, label);

            // assign control when custom validation is not required
            if (ControlType.CanServerValidate(inputType))
                validator.ControlToValidate = controlToValidate.ClientID;

            //assign attributes
            validator.ValidationGroup = validationGroup;
            validator.Text = x.HasAttribute("Text") == true ? x.GetText() : validator.Text;
            validator.ErrorMessage = x.HasAttribute("ErrorMessage") == true ? x.Attribute("ErrorMessage").Value : validator.ErrorMessage;

            // assign display type
            string display = x.HasAttribute("Display") == true ? x.Attribute("Display").Value : string.Empty;
            if (display == "Dynamic")
                validator.Display = ValidatorDisplay.Dynamic;
            else if (display == "Static")
                validator.Display = ValidatorDisplay.Static;
            else if (display == "None")
                validator.Display = ValidatorDisplay.None;

            return validator;
        }

        #endregion



        #region CreateControl

        protected Control CreateControl(string name, Control control, string type, string suffix)
        {
            string id = ControlBuilderHelper.CreateId(type, name + suffix);
            control.ID = id;
            return control;
        }

        #endregion



        #region CreateITextControl

        protected Control CreateITextControl(string name, ITextControl control, string type, string suffix)
        {
            string id = ControlBuilderHelper.CreateId(type, name + suffix);
            string text = !string.IsNullOrEmpty(suffix) ? name + " " + suffix : name;

            ((Control)control).ID = id;
            control.Text = text;
            return (Control)control;
        }

        #endregion



        #region CreateButton

        /// <summary>
        /// Create button with given id and text properties.
        /// </summary>
        /// <param name="id"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        protected Button CreateButton(string id, string text)
        {
            Button button = new Button();
            button.ID = id.ToLower();
            button.Text = text;
            return button;
        }

        #endregion



        #region CreateListControl

        protected ListControl CreateListControl(XElement field, ListControl lc, string type)
        {
            lc.ID = ControlBuilderHelper.CreateId(type, field.GetName());
            var xmlListItems = field.Descendants("Item");

            if (xmlListItems.Count() > 0)
            {
                List<ListItem> listItems = new List<ListItem>();
                foreach (var xmlItem in xmlListItems)
                {
                    string text = xmlItem.GetText();
                    string value = xmlItem.Attribute("Value").Value;
                    lc.Items.Add(new ListItem(text, value));
                }
                return lc;
            }

            var xmlProvider = field.Descendants("Provider").SingleOrDefault();
            if (xmlProvider != null)
            {
                //string providerType = xmlProvider.Attribute("DataSource").Value;
                string provider = xmlProvider.Attribute("Name").Value;
                var parameters = xmlProvider.Descendants("Parameter").ToList();
                List<ListItem> listItems = DataSourceProviderManager.Providers[provider].GetListItems(parameters);
                listItems.ForEach(x => lc.Items.Add(x));
            }

            return lc;
        }

        #endregion




        #region AddResource

        /// <summary>
        /// Adds an embedded resource to the page. 
        /// Resource types can be a link or a script.
        /// </summary>
        /// <param name="resource"></param>
        /// <param name="type"></param>
        public void AddResource(string resource, ResourceType type)
        {
            // get page from http context
            Page page = (System.Web.UI.Page)HttpContext.Current.CurrentHandler;

            // get resource
            string s = page.ClientScript.GetWebResourceUrl(this.GetType(), resource);

            // create literal 
            Literal l = new Literal();
            if (type == ResourceType.Style)
                l.Text = "<link type='text/css' rel='stylesheet' href='" + s + "' />";
            else
                l.Text = @"<script type=""text/javascript"" src=""" + s + @"""></script>";

            // add js
            page.Header.Controls.Add(l);
        }

        #endregion



        #region CreateEntryUpdateField

        /// <summary>
        /// Hardcode a hidden field to be used for entry updates.
        /// </summary>
        /// <param name="div"></param>
        public void CreateEntryUpdateField(HtmlGenericControl div, List<FormField> formFields)
        {
            XElement x = new XElement(ClientStrings.Default.FormsyEntryId);
            x.SetAttributeValue("Name", "FormsyEntryId");
            x.SetAttributeValue("Value", string.Empty);
            Control control = CreateHiddenField(x.GetName(), x.GetValue());
            div.Controls.Add(control);

            formFields.Add(new FormField(control.ID, ClientStrings.Default.FormsyEntryId, control, null, ControlType.HiddenField, false));
        }

        #endregion



        #region AddClass

        public void AddClass(HtmlControl control, string cssClass)
        {
            string classes = control.Attributes["class"];
            if (string.IsNullOrEmpty(classes))
                control.Attributes["class"] = cssClass;
            else
                control.Attributes["class"] = classes + " " + cssClass;
        }

        #endregion



        #region AddTypeAsClass

        /// <summary>
        /// Adds cssClass as the 2nd class in the div.
        /// </summary>
        /// <param name="div"></param>
        /// <param name="fieldType"></param>
        public void AddTypeAsClass(HtmlGenericControl div, string cssClass)
        {
            if (div.Attributes["class"] == null)
            {
                AddClass(div, cssClass);
                return;
            }

            List<string> cssClasses = div.Attributes["class"].Split(" ".ToCharArray()).ToList();

            if (cssClasses.Count == 0)
            {
                div.Attributes["class"] = cssClass.Flatten();
            }
            else if (cssClasses.Count == 1)
            {
                div.Attributes["class"] = div.Attributes["class"] + " " + cssClass.Flatten();
            }
            else
            {
                cssClasses.Insert(1, cssClass.Flatten());
                div.Attributes["class"] = string.Join(" ", cssClasses.ToArray());
            }
        }

        #endregion



        #region AddEnclosedLiteral

        /// <summary>
        /// Adds a literal enclosed by a div to the given containing element. 
        /// </summary>
        /// <param name="container"></param>
        /// <param name="controlType"></param>
        /// <param name="literal"></param>
        public Control AddEnclosedLiteral(HtmlGenericControl container, string controlType, string name, string text, string cssClass)
        {
            HtmlGenericControl control = CreateHtmlControl(controlType, name, cssClass);
            LiteralControl l = new LiteralControl(text);
            control.Controls.Add(l);
            container.Controls.Add(control);
            return control;
        }

        #endregion



        #region AddFormsyLogo

        public void AddFormsyLogo()
        {
            // register js for formsy link
            Page page = (Page)HttpContext.Current.CurrentHandler;
            page.ClientScript.RegisterClientScriptResource(GetType(), "Formsy.Core.Resources.Scripts.formsy.csv.js");

            page.ClientScript.RegisterStartupScript(GetType(), "FormsyLogoLink", "InsertLogoLink();", true);

            // create script for formsy logo
            StringBuilder logo = new StringBuilder();
            logo.AppendLine("(function(){");
            logo.AppendLine("var logo = document.getElementById('formsyLogo');");
            logo.Append("\tlogo.style.background='white url(\"");
            logo.Append(page.ClientScript.GetWebResourceUrl(GetType(), EmbededResource.AdminLogoImage));
            logo.AppendLine("\")';");
            logo.AppendLine("})();");

            // register script for formsy logo
            page.ClientScript.RegisterStartupScript(GetType(), "FormsyLogo", logo.ToString(), true);
        }

        #endregion
    }
}
